package cn.agiledata.bank.transaction.action;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import cn.agiledata.bank.account.service.AccountSummary;
import cn.agiledata.bank.common.dao.AccountTemplateInter;
import cn.agiledata.bank.common.dao.ActionTypeTemplate;
import cn.agiledata.bank.common.service.PermissionService;
import cn.agiledata.bank.common.service.SetUpUses;
import cn.agiledata.bank.common.util.Constant;
import cn.agiledata.bank.common.util.ConvertUtil;
import cn.agiledata.bank.common.util.ForeDict;
import cn.agiledata.bank.common.util.UniqueIdentityUtil;
import cn.agiledata.bank.common.util.WeatherUtil;
import cn.agiledata.bank.hibernateBean.Account;
import cn.agiledata.bank.hibernateBean.ActionType;
import cn.agiledata.bank.hibernateBean.SubAccount;
import cn.agiledata.bank.hibernateBean.Transaction;
import cn.agiledata.bank.transaction.exception.TransactionException;
import cn.agiledata.bank.transaction.form.MultiStepForm;
import cn.agiledata.bank.transaction.form.SubAccountTransferForm;
import cn.agiledata.bank.transaction.service.GetTransaction;
import cn.agiledata.bank.transaction.service.GetTransactionImpl;
import cn.agiledata.bank.transaction.service.TransactionFactory;
import com.vnv.infrastructure.action.IPBBaseAction;
import com.vnv.infrastructure.logic.IPBAppFactory;

/**
 * 子账户间转账Action
 * 
 * @author maxianbo
 * 
 */
public class SubAccountTransferAction extends IPBBaseAction {

    protected boolean isFieldValidatable(ActionMapping mapping,
            ActionForm actionForm, HttpServletRequest request,
            HttpServletResponse response) {
        return false;
    }

    protected ActionForward getFieldErrorForward(ActionMapping mapping,
            ActionForm actionForm, HttpServletRequest request,
            HttpServletResponse response) {
        SubAccountTransferForm form = (SubAccountTransferForm) actionForm;
        return returnStep1(mapping, form, request);
    }

    /**
     * 分发调度
     */
    public final ActionForward assign(ActionMapping mapping,
            ActionForm actionForm, HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        MultiStepForm form = (MultiStepForm) actionForm;
        int step = form.getStep();
        ActionForward forward;
        switch (step) {
        case 0: // 第0步准备初始化数据
            forward = prepare(mapping, actionForm, request, response);
            break;
        case 1: // 第1步进行子账户转账
            forward = transfer(mapping, actionForm, request, response);
            break;
        default: // 其它步骤序数跳转到第0步，进入新的子账户转账流程，防止错误的步骤序数被提交
            form.setStep(0);
            forward = prepare(mapping, actionForm, request, response);
        }
        // 设置新的步骤序数，最大步骤序数为1
        form.setNextStep(1);
        return forward;
    }

    private AccountTemplateInter getAccountTemplate() {
        return (AccountTemplateInter) IPBAppFactory
                .getObj(ForeDict.ACCOUNT_TEMPLATE);
    }

    /**
     * 获取当前账户
     */
    private Account getCurrentAccount(HttpServletRequest request) {
        long accountId = WeatherUtil.getAccountIdFromSession(request);
        return getAccountTemplate().getAccount(String.valueOf(accountId));
    }

    /**
     * 加载子账户列表
     */
    private Collection loadSubAccountList(HttpServletRequest request,
            PermissionService permissionService) {
        Account account = getCurrentAccount(request);
        SubAccount defaultSubAccount = account.getDefaultSubAccount();
        if (isCorpAccount(request)) { // 企业操作员
            // 获取当前企业操作员具有子账户转账权限的子账户列表
            List subAccounts = permissionService.getSubAccounts(request,
                    Constant.PERMIS_TYPE_TRANSFER, defaultSubAccount);
            request.setAttribute("subAccounts", subAccounts);
            return subAccounts;
        } else { // 个人用户
            // 获取当前个人用户的所有子账户列表
            Set subAccounts = account.getSubAccounts();
            request.setAttribute("subAccounts", subAccounts);
            return subAccounts;
        }
    }

    public ActionForward prepare(ActionMapping mapping, ActionForm actionForm,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        Account account = getCurrentAccount(request);
        // 判断当前用户是否具有提现权限
        PermissionService permissionService = PermissionService
                .getPermissionService();
        if (!permissionService.hasPermission(request,
                Constant.PERMIS_TYPE_TRANSFER)) {
            throw TransactionException.NO_PERMISSION;
        }
        Collection subAccounts = loadSubAccountList(request, permissionService);
        // 付款子账户默认选择默认子账户
        SubAccountTransferForm form = (SubAccountTransferForm) actionForm;
        if (form.getDebitSubAccountId() == 0) {
            SubAccount debitSubAccount = account.getDefaultSubAccount();
            form.setDebitSubAccountId(debitSubAccount.getId().longValue());
        }
        // 收款子账户默认选择子账户列表中的第一个
        if (form.getCreditSubAccountId() == 0) {
            SubAccount creditSubAccount = (SubAccount) subAccounts.iterator()
                    .next();
            form.setCreditSubAccountId(creditSubAccount.getId().longValue());
        }
        loadSubAccountBalance(request, form);
        return mapping.findForward(ForeDict.FORWARD_STEP_1);
    }

    /**
     * 获取付款子账户和收款子账户余额
     */
    private void loadSubAccountBalance(HttpServletRequest request,
            SubAccountTransferForm form) {
        String debitBalance = getAccountTemplate().accountMoney(
                String.valueOf(form.getDebitSubAccountId()));
        request.setAttribute("debitSubAccountBalance", debitBalance);
        String creditBalance = getAccountTemplate().accountMoney(
                String.valueOf(form.getCreditSubAccountId()));
        request.setAttribute("creditSubAccountBalance", creditBalance);
    }

    /**
     * 保存交易
     */
    private void saveTransaction(Transaction trans) {
        GetTransaction getTran = new GetTransactionImpl();
        String actionType = trans.getActionType().getId().toString();
        TransactionFactory tf = getTran.getTransaction(actionType);
        tf.saveTransaction(trans);
    }

    private ActionTypeTemplate getActionTypeTemplate() {
        return (ActionTypeTemplate) IPBAppFactory
                .getObj(ForeDict.ACTION_TYPE_TEMPLATE);
    }

    /**
     * 获取子账户转账的交易类型对象
     */
    private ActionType getActionType() {
        long actionTypeId = Long.parseLong(Constant.ACTION_TYPE_H);
        return getActionTypeTemplate().getActionTypeById(actionTypeId);
    }

    /**
     * 判断当前用户是否企业用户
     */
    protected final boolean isCorpAccount(HttpServletRequest request) {
        Account account = getCurrentAccount(request);
        return Constant.ACCOUNT_TYPE_CORPORATION.equals(account
                .getAccountType());
    }

    /**
     * 根据子账户转账数据创建交易对象
     * 
     * @throws TransactionException
     */
    private Transaction createTransaction(SubAccountTransferForm form)
            throws TransactionException {
        // 新建交易
        Transaction trans = new Transaction();
        AccountTemplateInter at = getAccountTemplate();
        // 付款方：付款子账户
        String debitSubAccountId = String.valueOf(form.getDebitSubAccountId());
        SubAccount debitSubAccount = at.getSubAccount(debitSubAccountId);
        trans.setDebit(debitSubAccount);
        // 收款方：收款子账户
        String creditSubAccountId = String
                .valueOf(form.getCreditSubAccountId());
        SubAccount creditSubAccount = at.getSubAccount(creditSubAccountId);
        trans.setCredit(creditSubAccount);
        // 校验收付方是否同一账户下的子账户
        if (!debitSubAccount.getAccount().getId().equals(
                creditSubAccount.getAccount().getId())) {
            throw TransactionException.NOT_THE_SAME_ACCOUNT;
        }
        // 交易状态：交易成功
        trans.setTransStatus(Constant.TRANS_STATUS_TRANSACTIONSUCCESS);
        // 生成交易编号
        trans.setTransId(UniqueIdentityUtil.getTransactionSequence());
        // 交易类型
        trans.setActionType(getActionType());
        // 非担保交易
        trans.setTradeType(Constant.TRADE_TYPE_NOASSURE);
        // 转账金额
        trans.setAmount(new Double(form.getAmount()));
        // 封装插入日期和修改日期
        WeatherUtil.fillCreateAndUpdateInfo(trans, debitSubAccount.getAccount()
                .getId().toString());
        // 交易开始时间
        trans.setBeginDate(new Date());
        // 内部状态：进行实际转账操作
        trans.setInsideStatus(Constant.INSIDE_STATUS_YES);
        return trans;
    }

    /**
     * 校验金额的格式和数值
     * 
     * @param amountValue
     *            字符串型金额值
     * @return Double型金额值
     * @throws TransactionException
     *             如果金额格式错误或金额值小于等于0
     */
    private Double validateAmount(String amountValue)
            throws TransactionException {
        try {
            Double amount = new Double(amountValue);
            if (amount.doubleValue() <= 0) {
                throw TransactionException.INVALID_AMOUT;
            }
            return amount;
        } catch (NumberFormatException e) {
            throw TransactionException.INVALID_AMOUT;
        }
    }

    /**
     * 校验子账户余额
     */
    private void validateSubAccountBalance(String subAccountId, Double amount)
            throws TransactionException {
        if (getAccountTemplate().compareAccountMoney(subAccountId, amount) != 0) {
            throw TransactionException.LACK_OF_BALANCE;
        }
    }

    private ActionForward returnStep1(ActionMapping mapping,
            SubAccountTransferForm form, HttpServletRequest request) {
        // 跳转到第1步，之前重新装载子账户列表
        PermissionService permissionService = PermissionService
                .getPermissionService();
        loadSubAccountList(request, permissionService);
        // 设置为上一步的步骤序数，防止序数与步骤不同步
        form.setPreviousStep();
        loadSubAccountBalance(request, form);
        return mapping.findForward(ForeDict.FORWARD_STEP_1);
    }

    public ActionForward transfer(ActionMapping mapping, ActionForm actionForm,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        SubAccountTransferForm form = (SubAccountTransferForm) actionForm;
        try {
            Double amount = validateAmount(form.getAmount());
            String debitSubAccountId = String.valueOf(form
                    .getDebitSubAccountId());
            validateSubAccountBalance(debitSubAccountId, amount);
            Transaction trans = createTransaction(form);
            // 如果是企业用户记录其操作员
            if (isCorpAccount(request)) {
                AccountSummary accountsummary = WeatherUtil
                        .getLoingInfoFromSession(request);
                trans.setOperatorSeq(accountsummary.getOperatorCode()
                        .toString());
            }
            try {
                saveTransaction(trans);
            } catch (RuntimeException e) {
                throw TransactionException.TRANSACTION_FAILED;
            }
            request.setAttribute("transaction", trans);
            SetUpUses ss = new SetUpUses();
            String url = WeatherUtil.getRootFromSession(request);
            ss.sendSetup(trans, trans.getCredit(), Constant.ACTION_TYPE_H,
                    trans.getDebitFee().toString(), ConvertUtil.parseDec(
                            new Double(trans.getAmount().doubleValue()
                                    - trans.getDebitFee().doubleValue()),
                            "0.00"), url, null);
        } catch (TransactionException e) {
            // 处理业务逻辑异常
            handleAppException(mapping, actionForm, request, response, e);
            return returnStep1(mapping, form, request);
        }
        return mapping.findForward(ForeDict.FORWARD_STEP_2);
    }

}